package com.chiangleoi.appointment.appointments;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chiangleoi.appointment.model.SiteInfo;
import com.chiangleoi.appointment.model.SiteJsonInfo;
import com.chiangleoi.appointment.model.UserJson;
import com.chiangleoi.appointment.model.UserJsonMap;
import com.chiangleoi.appointment.model.vo.SubscribeUserRequest;
import com.chiangleoi.appointment.utils.*;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.net.Authenticator;

import okhttp3.*;
import org.springframework.util.CollectionUtils;

import javax.net.ssl.*;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

public class GuDingBadmintonTrainKillForProxy {

    static final String url = "https://jntyzx.cn:8443/GYM-JN/multi/Subscribe/addSubscribe";//指定URL

    private static boolean isRunning = true;
    //    private static boolean isCall = true;
    private static boolean isCall = true;
    private static boolean isMock = false;

    // 用户名密码认证(私密代理/独享代理)
    final static String ProxyUser = "d2859987908";
    final static String ProxyPass = "1auxzpkz";


    // 创建一个信任所有证书的TrustManager
    final static TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[]{};
                }
            }
    };

    public static void main(String[] args) throws Exception {
        printDebug();

        System.out.println("---------------------- 准备获取预订的场地 -------------------------");
        Date today = new Date();
        DateTime dateTime = DateUtil.offsetDay(today, 1);
        boolean isWeekend = DateUtil.isWeekend(dateTime);

        List<SiteJsonInfo> siteJsonInfoList = randomSite(isWeekend);
        SiteJsonInfo siteJsonInfo = siteJsonInfoList.get(0);

        String appointments = siteJsonInfo.getAppointments();
        System.out.println(appointments + "是否为周末:" + isWeekend);

        ObjectMapper objectMapper = new ObjectMapper();
        String siteJsonInfoListJSON = objectMapper.writeValueAsString(siteJsonInfoList);
        System.out.println("当前预约场地列表JSON:" + siteJsonInfoListJSON);

        List<UserJson> userList = getUserList();
        List<UserJson> killUserList = getKillUserList();
        String svCiphertext = SvCipherUtils.getSvCiphertext(siteJsonInfoListJSON);

        System.out.println("---------------------- 组装请求JSON串 -------------------------");

        List<UserJsonMap> postRequestJsonList = new ArrayList<UserJsonMap>();

        // 抢跑列表
        System.out.println("---------------------- 抢跑列表 -------------------------");
        for (UserJson userJson : userList) {
            System.out.println("抢跑者:" + userJson.getNickName());
            UserJsonMap userMap = new UserJsonMap();
            userMap.setUserName(userJson.getNickName());
            String userPostJson = getUserPostJson(userJson, siteJsonInfo.getAppointments(), siteJsonInfo, svCiphertext);
            userMap.setPostData(userPostJson);
            postRequestJsonList.add(userMap);
        }

        // 杀牛列表
        List<UserJsonMap> postKillRequestJsonList = new ArrayList<>();
        System.out.println("---------------------- 杀牛列表 -------------------------");
        for (UserJson userJson : killUserList) {
            System.out.println("被杀的牛:" + userJson.getNickName());
            UserJsonMap userMap = new UserJsonMap();
            userMap.setUserName(userJson.getNickName());
            String userPostJson = getUserPostJson(userJson, siteJsonInfo.getAppointments(), siteJsonInfo, svCiphertext);
            userMap.setPostData(userPostJson);
            postKillRequestJsonList.add(userMap);
        }

        printDebug();
        System.out.println("---------------------- 请求JSON组装完毕 -------------------------");
        System.out.println("---------------------- 准备定时请求至接口 -------------------------");


        call(postRequestJsonList, postKillRequestJsonList);
    }

    private static List<UserJson> getKillUserList() {
        List<UserJson> userJsons = new ArrayList<>();
        if (isMock) {
            userJsons.add(new UserJson("1876433582606581762", "o21MO1WfE7tccPbef6Odc", "杀杀杀"));
        } else {
            // 阿勇
            //烂
            userJsons.add(new UserJson("1874984022122233858", "o21MX46zGCD1Moj3KTyL0X35vRRA", "任慧"));
        }
        return userJsons;
    }


    private static List<UserJson> getUserList() {
        List<UserJson> userJsons = new ArrayList<>();
        if (isMock) {
            userJsons.add(new UserJson("1876433582606581762", "o21MO1WfE7tccPbef6Odc", "李宪宪"));
        }
        return userJsons;
    }

    public static String getUserPostJson(UserJson userJson, String appointments,
                                         SiteJsonInfo siteJsonInfo, String svCiphertext) {
        SubscribeUserRequest request = new SubscribeUserRequest();
        request.setBookTime(appointments);

        List<SiteJsonInfo> subscribeVos = new ArrayList<>();
        subscribeVos.add(siteJsonInfo);
        request.setSubscribeVos(subscribeVos);

        request.setPaymentMethod("1");
        request.setSvCiphertext(svCiphertext);
        request.setJsonObject(userJson);

        String requestJson = JSON.toJSONString(request);
        System.out.println("当前用户:" + userJson.getNickName() + ", 当前用户的JSON:" + requestJson);
        return requestJson;
    }

    private static List<SiteJsonInfo> randomSite(boolean isWeekend) throws Exception {
        SubscribeUtils subscribeUtils = new SubscribeUtils();
        List<SiteInfo> subscribeList = subscribeUtils.getSubscribeList();

        if (CollectionUtils.isEmpty(subscribeList)) {
            throw new RuntimeException("场地获取失败");
        }

        System.out.println("全部场地:" + JSON.toJSONString(subscribeList));


        List<SiteInfo> subscribeEmptyList = subscribeList.stream()
                .filter(siteInfo -> !"0".equals(siteInfo.getContacts()))
                .filter(siteInfo -> !"培训".equals(siteInfo.getContacts()))
                .filter(siteInfo -> !"系统锁定".equals(siteInfo.getContacts()))
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(subscribeEmptyList)) {
            throw new RuntimeException("场地获取失败");
        }

        SiteInfo siteInfo = subscribeEmptyList.get(0);
        System.out.println("从接口获取的siteInfo/JSON:" + JSON.toJSONString(siteInfo));
        SiteJsonInfo siteJsonInfo = BeanCopyUtil.copy(siteInfo, SiteJsonInfo.class);
        siteJsonInfo.setId(0);
        String appointments = siteInfo.getAppointments();
        System.out.println("当前预约时间:" + appointments);
        System.out.println("当前预约场地:" + siteInfo.getPlaceName());
        System.out.println("当前预约时间段:" + siteInfo.getSjName());

        List<SiteJsonInfo> siteJsonInfoList = new ArrayList<>();
        siteJsonInfoList.add(siteJsonInfo);

        return siteJsonInfoList;
    }

    private static void printDebug() {
        if (isCall) {
            System.out.println("【启用】接口调用, isCall:" + isCall);
        } else {
            System.out.println("【不启用】接口调用, isCall:" + isCall);
        }

    }

    private static void call(List<UserJsonMap> postRequestJsonList,
                             List<UserJsonMap> postKillRequestJsonList) throws Exception {
        String callStatus = isCall == true ? "开启" : "未开启";
        String runningStatus = isRunning == true ? "运行" : "未运行";
        String mockStatus = isMock == true ? "Mock" : "非Mock";
        System.out.println("isCall的是否开启:【" + callStatus + "】");
        System.out.println("isRunning的是否运行:【" + runningStatus + "】");
        System.out.println("isMock:【" + mockStatus + "】");

        // 创建自定义的 Dispatcher
        Dispatcher dispatcher = new Dispatcher();
        // 设置最大并发请求数量（可根据需求修改）
        dispatcher.setMaxRequests(100);
        dispatcher.setMaxRequestsPerHost(50);
        // 创建OkHttpClient
        OkHttpClient client = new OkHttpClient().newBuilder().dispatcher(dispatcher).build();
        for (UserJsonMap userJsonMap : postKillRequestJsonList) {
            if (isCall) {
                sendKillData(userJsonMap, 10);
            }
        }

    }


    private static void sendKillData(UserJsonMap userJsonMap, int times) throws Exception {

        final SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

        // 创建一个信任所有主机名的HostnameVerifier
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        for (int i = 0; i <= times; i++) {
            Map<String, String> getdps = getdps(1);
            sendPostToProxy(userJsonMap, getdps.get("ip"), Integer.parseInt(getdps.get("port")));
        }
    }

    public static String sendPostToProxy(UserJsonMap userJsonMap, String ip, int port) {
        try {
            // 设置请求验证信息
            Authenticator.setDefault(new ProxyAuthenticator(ProxyUser, ProxyPass));
            System.out.println("【杀牛者】:" + userJsonMap.getUserName() + ",时间:" + DateUtils.format(new Date()));
            System.out.println("当前json:【" + userJsonMap.getPostData() + "】发送请求时间");
            long startTime = System.currentTimeMillis();
            // 发送请求
//            String result = HttpRequest.post(url)
//                    .header("Content-Type", "application/json")//头信息，多个头信息多次调用此方法即可
//                    .header("Host", "jntyzx.cn:8443")
//                    .header("Connection", "keep-alive")
//                    .header("Accept-Encoding", "gzip,compress,br,deflate")
//                    .header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.49(0x18003137) NetType/WIFI Language/zh_CN")
//                    .header("Referer", "https://servicewechat.com/wxb3c812f7a3ebf851/58/page-frame.html")
//                    .body(json)
//                    .setHttpProxy(ip, port)
//                    .timeout(20000) // 设置超时，毫秒
//                    .execute().body();
            String result = "123";
            long times = System.currentTimeMillis() - startTime;
            System.out.println(result);
            System.out.println(userJsonMap.getUserName() + ",发送请求结束时间:" + DateUtils.format(new Date()) + ",用时:" + times);
            return result;
        } catch (IORuntimeException e) {
            System.out.println("发送请求失败IORuntimeException:" + e.getMessage());
        } catch (Exception e) {
            System.out.println("发送请求失败Exception:" + e.getMessage());
        }
        return "请求错误";
    }

    public static Map<String, String> getdps(int num) {
        Map<String, String> ipMap = new HashMap<>();
        // 获取私密代理IP API
        String apiUrl = "https://dps.kdlapi.com/api/getdps/?pt=1&format=json&sep=1&";
        // 请求参数
        String secretId = "o82qrnb4z0s8y6j9qvyw";
        String signature = "p93f1o4fn6zht9sa6aryu9wpfp2el8dm";
        String params = "secret_id=" + secretId + "&signature=" + signature + "&num=" + num;
        String body = HttpRequest.get(apiUrl + params).execute().body();
        System.out.println("ip代理池:" + body);
        JSONObject jsonObject = JSONObject.parseObject(body);
        JSONObject data = jsonObject.getJSONObject("data");
        if (data != null) {
            List<String> ipList = data.getJSONArray("proxy_list").toJavaList(String.class);
            for (String ip : ipList) {
                String[] split = ip.split(":");
                ipMap.put("ip", split[0]);
                ipMap.put("port", split[1]);
            }
        }
        return ipMap;
    }

}
